package org.droidplanner.android.fragments.widget.video

import android.content.Context
import android.graphics.SurfaceTexture
import android.util.AttributeSet
import android.view.Surface
import android.view.TextureView
import com.shenyaocn.android.OpenH264.Decoder
import com.skydroid.fpvplayer.SkySurfaceReader
import com.skydroid.fpvplayer.ffmpeg.FFmpegConstants
import com.skydroid.fpvplayer.ffmpeg.FFmpegParser
import com.skydroid.fpvplayer.ffmpeg.FFmpegStreamClient
import com.skydroid.fpvplayer.ffmpeg.FrameInfo
import java.util.concurrent.ArrayBlockingQueue
import java.util.concurrent.TimeUnit

/**
 * @author 咔一下
 * @date 2023/7/20 16:01
 * @email 1501020210@qq.com
 * @describe
 */
class H264FPVReaderWidget @JvmOverloads constructor(
    context: Context, attrs: AttributeSet? = null
) : TextureView(context, attrs) {

    private val fFmpegParser = FFmpegParser()
    private val videoDecoder = Decoder()
    private var isTextureAvailable = false
    private var videoWidth:Int = 1280
    private var videoHeight:Int = 720
    private var videoFrameRate:Int = 25
    private var readStreamToBuffThread:ReadStreamToBuffThread? = null
    private var readBuffToDecodecThread: ReadBuffToDecodecThread? = null
    private val queue = ArrayBlockingQueue<FrameInfo>(30 * 60)
    private var skySurfaceReader = SkySurfaceReader()

    var usingMediaCodec = false

    init {

    }

    @Synchronized
    fun start(width:Int,height:Int,frameRate: Int){
        this.videoWidth = width
        this.videoHeight = height
        this.videoFrameRate = frameRate
        surfaceTextureListener = object : SurfaceTextureListener {
            override fun onSurfaceTextureAvailable(
                surface: SurfaceTexture,
                width: Int,
                height: Int
            ) {
                videoDecoder.create()
                val mSurface = Surface(surface)
                skySurfaceReader.setSurface(mSurface)
                isTextureAvailable = true
            }

            override fun onSurfaceTextureSizeChanged(
                surface: SurfaceTexture,
                width: Int,
                height: Int
            ) {
            }

            override fun onSurfaceTextureDestroyed(surface: SurfaceTexture): Boolean {
                stop()
                videoDecoder.destroy()
                skySurfaceReader.releaseSurface()
                isTextureAvailable = false
                return false
            }

            override fun onSurfaceTextureUpdated(surface: SurfaceTexture) {}
        }
        fFmpegParser.release()
        fFmpegParser.initParser(FFmpegConstants.VIDEO_CODEC_TYPE_H264)
        readBuffToDecodecThread?.interrupt()
        readBuffToDecodecThread = ReadBuffToDecodecThread()
        readBuffToDecodecThread?.start()
        readStreamToBuffThread?.interrupt()
        readStreamToBuffThread = ReadStreamToBuffThread()
        readStreamToBuffThread?.start()
    }

    @Synchronized
    fun stop(){
        fFmpegParser.release()
        readStreamToBuffThread?.interrupt()
        readStreamToBuffThread = null
        queue.clear()
        readBuffToDecodecThread?.syncClose()
        readBuffToDecodecThread = null
    }

    fun sendFrame(frame:ByteArray){
        fFmpegParser.sendToParser(frame,frame.size)
    }

    private inner class ReadStreamToBuffThread : Thread(){

        var isRun = false

        override fun run() {
            super.run()
            isRun = true
            while (isRun){
                try {
                    val frameInfo = fFmpegParser.frame
                    if (frameInfo != null){
                        queue.put(frameInfo)
                    }else{
                        Thread.sleep(5)
                    }
                }catch (e:Exception){}
            }
        }

        override fun interrupt() {
            isRun = false
            try {
                super.interrupt()
            }catch (e:Exception){}

        }
    }

    private inner class ReadBuffToDecodecThread: Thread(){

        private var isRun = false

        override fun run() {
            super.run()
            while(isRun){
                try {
                    val frameInfo = queue.poll(5L, TimeUnit.MILLISECONDS)
                    if (frameInfo != null){
                        if (videoDecoder.decodeI420(frameInfo.data,frameInfo.frameSize)){
                            val buff = ByteArray(videoDecoder.frameHeight * videoDecoder.frameWidth * 3 / 2)
                            videoDecoder.getFrameI420(buff)
                            //这里可以优化，当宽度高度改变时再设置
                            skySurfaceReader.setSize(videoDecoder.frameWidth,videoDecoder.frameHeight)
                            skySurfaceReader.readerYUV(FFmpegConstants.PIXEL_FORMAT_YUV420P,buff)
                        }
                    }
                } catch (e:Exception) {

                } finally {

                }
            }
        }

        @Synchronized
        override fun start() {
            isRun = true
            super.start()
        }

        @Synchronized
        override fun interrupt() {
            isRun = false
            try {
                super.interrupt()
            }catch (e:Exception){}
        }

        @Synchronized
        fun syncClose(){
            isRun = false
            try {
                join()
            }catch (e:Exception){}
            try {
                super.interrupt()
            }catch (e:Exception){}
        }
    }
}